using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Serialization;

using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;

using System.Web.Security;
using System.Web;
using System.DirectoryServices;
using System.Security.Principal;
using System.Net.Mail;
using System.Data.SqlClient;
using System.Text.RegularExpressions;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Utilities;
using System.Configuration;
using System.Diagnostics;
using EAT.Common;

namespace EAT.ExternalCollaboration
{

    // This file contains the classes for:
    //     ChangeQAPage       - this is the page the external user is redirected to when we
    //                         think he needs to do something. Typically this is first logon,
    //                         triggered by a sentinel value in the membership password reset
    //                         Q/A attribute. The user should also get sent here if their password
    //                         is administratively set (when first provisioned) or reset.
    //     LogonPage         - This is the class that overrides or extends the default behaviour
    //                         of the membership logon control.
    //     PasswordResetPage - Self explanatory.

    
    /*++
    class ChangeQAPage
     
    --*/

    public class ChangeQAPage : Microsoft.SharePoint.WebControls.LayoutsPageBase
    {
        protected Label lblPassword;
        protected TextBox tbPassword;
        protected Label lblNewPassword;
        protected TextBox tbNewPassword;
        protected Label lblConfirmPassword;
        protected TextBox tbConfirmPassword;
        protected Label lblQuestion;
        protected TextBox tbQuestion;
        protected Label lblAnswer;
        protected TextBox tbAnswer;
        protected Label lblChange;
        protected Label lblQAInstructions;
        protected Label lblPwdInstructions;
        protected Label lblProfileInstructions;
        protected Button btnChange;
        protected Label lblCompany;
        protected TextBox tbCompany;
        protected Label lblFirstName;
        protected TextBox tbFirstName;
        protected Label lblLastName;
        protected TextBox tbLastName;
        protected Label lblPhoneNumber;
        protected TextBox tbPhoneNumber;

        cUserManager UM;
        bool bQA;
        bool bPwd;
        bool bProfile;


        void Page_Init()
        {
            bQA = false;
            bPwd = false;
            bProfile = false;

            SqlManager SqlM = new SqlManager();
            long PwdWarningDays = long.Parse(SqlM.GetEntry("Config", "PwdExpiration"));

            try
            {
                MembershipUser u = Membership.GetUser();

                UM = new cUserManager(
                           ConfigurationManager.ConnectionStrings["ADAMConnectionString"].ConnectionString
                           );

                if (UM.UserMustSetProfileInformation(u))
                {
                    bProfile = true;
                    lblCompany.Visible = true;
                    tbCompany.Visible = true;

                    lblFirstName.Visible = true;
                    tbFirstName.Visible = true;

                    lblLastName.Visible = true;
                    tbLastName.Visible = true;

                    lblPhoneNumber.Visible = true;
                    tbPhoneNumber.Visible = true;

                    lblProfileInstructions.Text = Resources.cqaEnterProfileInfoText;
                }
                else
                {
                    lblCompany.Visible = false;
                    tbCompany.Visible = false;

                    lblFirstName.Visible = false;
                    tbFirstName.Visible = false;

                    lblLastName.Visible = false;
                    tbLastName.Visible = false;

                    lblPhoneNumber.Visible = false;
                    tbPhoneNumber.Visible = false;
                }

                if (UM.UserMustSetSecretQuestion(u))
                {
                    bQA = true;
                    lblPassword.Visible = true;
                    tbPassword.Visible = true;

                    lblQuestion.Visible = true;
                    tbQuestion.Visible = true;

                    lblAnswer.Visible = true;
                    tbAnswer.Visible = true;
                    
                    lblQAInstructions.Text = Resources.cqaQAInstructionsText;
                }
                else
                {
                    lblQuestion.Visible = false;
                    tbQuestion.Visible = false;

                    lblAnswer.Visible = false;
                    tbAnswer.Visible = false;
                }

                if (UM.UserMustSetPassword(u, PwdWarningDays))
                {
                    bPwd = true;

                    lblPassword.Visible = true;
                    tbPassword.Visible = true;

                    lblNewPassword.Visible = true;
                    tbNewPassword.Visible = true;

                    lblConfirmPassword.Visible = true;
                    tbConfirmPassword.Visible = true;

                    if (UM.PasswordNeverSet(u))
                    {
                        lblPwdInstructions.Text = Resources.cqaNeverSetPasswordText;
                    }
                    else
                    {
                        lblPwdInstructions.Text = String.Format(Resources.cqaPasswordExpiresSoonText, UM.DaysUntilPasswordExpires(u).ToString());
                    }
                }
                else
                {
                    lblNewPassword.Visible = false;
                    tbNewPassword.Visible = false;

                    lblConfirmPassword.Visible = false;
                    tbConfirmPassword.Visible = false;
                }
                if (bQA == false && bPwd == false)
                {
                    lblPassword.Visible = false;
                    tbPassword.Visible = false;
                }
            }
            catch (Exception ex)
            {
                lblChange.Text += ex.Message;
            }
        }

        public void btnChange_Click(object sender, EventArgs e)
        {
            SPHelper SPH = new SPHelper();
            lblChange.Text = "";
            bool fSuccess = false;
            MembershipUser u = null;

            try
            {
                u = Membership.GetUser();

                if (bQA)
                {
                    if (tbPassword.Text == tbQuestion.Text || tbPassword.Text == tbAnswer.Text)
                    {
                        throw new Exception(Resources.cqaCannotChangeQAText);
                    }

                    bool b;
                    b = u.ChangePasswordQuestionAndAnswer(
                              tbPassword.Text, 
                              HttpUtility.HtmlEncode(tbQuestion.Text), 
                              HttpUtility.HtmlEncode(tbAnswer.Text)
                              );
                    if (!b)
                    {
                        throw new Exception(Resources.cqaCannotChangeQAText);
                    }
                }

                if (bPwd)
                {
                    if (tbNewPassword.Text != tbConfirmPassword.Text)
                    {
                        throw new Exception(Resources.cqaPasswordsDoNotMatchText);
                    }
                    if (tbNewPassword.Text == "" || tbConfirmPassword.Text == "")
                    {
                        throw new Exception(Resources.cqaNoPasswordEnteredText);
                    }
                    // this is somewhat redundant as the ChangePassword below will validate
                    // the user's password as well. This does provide a better error message,
                    // however, so I'm leaving it here.
                    if (Membership.ValidateUser(u.UserName, tbPassword.Text) == false)
                    {
                        throw new Exception(Resources.cqaWrongPasswordEnteredText);
                    }
                    
                    try
                    {
                        UM.ChangePassword(u, tbPassword.Text, tbNewPassword.Text);
                    }
                    catch (System.Reflection.TargetInvocationException)
                    {
                        // I think that the only error we have at this point is policy constraint violation
                        throw new Exception(Resources.passwordConstraintViolationText);
                    }
                }

                if (bProfile)
                {
                    if (tbCompany.Text == "")
                    {
                        throw new Exception(Resources.ECNoCompanyNameText);
                    }
                    if (tbFirstName.Text == "")
                    {
                        throw new Exception(Resources.ECNoFirstNameText);
                    }
                    if (tbLastName.Text == "")
                    {
                        throw new Exception(Resources.ECNoLastNameText);
                    }
                    if (tbPhoneNumber.Text == "")
                    {
                        throw new Exception(Resources.ECNoPhoneNumberText);
                    }   

                    //
                    // Set company, phone, and name information.
                    //
                    UM.SetProfileInformation(
                        u, 
                        tbCompany.Text, 
                        tbFirstName.Text, 
                        tbLastName.Text, 
                        tbPhoneNumber.Text
                        );
                }
                fSuccess = true;
            }
            catch (Exception Ex)
            {
               lblChange.Text += Ex.Message;
               return;
            }
            finally
            {
                if (fSuccess )
                {
                    Response.Redirect(FormsAuthentication.GetRedirectUrl(u.UserName, false));
                }
            }
        } 
    }

   
    
    /*++
    class LoginPage
    
    The LoginPage class supports the login.aspx, and provides codebehind for password reset.
     
    --*/

    public class LoginPage : Microsoft.SharePoint.WebControls.UnsecuredLayoutsPageBase
    {
        protected SqlManager SqlM;
        protected EAT.Common.cUserManager UM;
        //
        // Button to present credentials.
        //
        protected System.Web.UI.WebControls.Button btnLogin;

        //
        // Label to display information in the event of an error.
        //
        protected System.Web.UI.WebControls.Label lblLogin;
        protected System.Web.UI.WebControls.Login LoginControl;
        protected override bool AllowAnonymousAccess { get { return true; } }
        protected override bool AllowNullWeb { get { return true; }  }
        protected System.Web.UI.WebControls.HyperLink hlPasswordRecovery;

        public LoginPage()
        {
            SqlM = new SqlManager();
            UM = new cUserManager(
                      ConfigurationManager.ConnectionStrings["ADAMConnectionString"].ConnectionString
                      );
        }

        protected void PasswordRecovery_Init()
        {
            string sspr = SqlM.GetEntry("Config", "SelfServicePwdResetEnabled");
            
            if (sspr.ToLower() == "true")
            {
                hlPasswordRecovery.Visible = true;
            }
            else
            {
                hlPasswordRecovery.Visible = false;
            }   
        }

        protected void PasswordRecovery_OnClick(object sender, EventArgs e)
        {
            Response.Redirect("/_layouts/ExternalCollaboration/PasswordReset.aspx");
        }

        //
        // This routine verifies that the secret question has been updated.  
        // The user is redirected as appropriate.
        //
        protected void VerifySecurityProfile(object sender, EventArgs e)
        {
            bool fGoToProfile = false;

            try
            {
                // SqlManager does it's own revert
                SqlManager SqlM = new SqlManager();
                long PwdWarningDays = long.Parse(SqlM.GetEntry("Config", "PwdExpiration"));

                MembershipUser u = Membership.GetUser(
                                                  LoginControl.UserName,
                                                  false
                                                  );
                
                if (UM.UserMustSetPassword(u, PwdWarningDays))
                {
                    fGoToProfile = true;
                }

                //
                // If the password question is set to the sentinel then pass the user
                // on to the pwd q change page.
                //
                if (UM.UserMustSetSecretQuestion(u) || UM.UserMustSetProfileInformation(u))
                {
                    //
                    // bugbug
                    // This method may prove too brittle.  In the case that the question isn't set yet,
                    // the user is redirected to the site they requested (eg. "collabextra/sites/mysite")
                    // + path to changeqa.aspx + the returnurl.  If the original return url isn't a top level
                    // site then this won't work.  An alternate method would be to force the destination url of
                    // the forms tag in web.config to point to changeqa.aspx, and redirect from there.
                    //

                    fGoToProfile = true;
                }
            }
            catch
            {
            }
            finally
            {
                if (fGoToProfile)
                {
                    // Redirecting from here to a QA page is hard. We have to make sure that the page is loaded under a site collection
                    // where the user has been given access. For the root site collection this is easy and nothing special has to
                    // happen. For the case where the site collection where the user can go is /sites/nickv then we have to send the
                    // user to the QA page at the right URL, for example: /sites/nick1/_layouts/ExternalCollaboration/changeqa.aspx?ReturnUrl=<source URL>

                    // For logon to non-root sites, a typical URL redirect from the logon page looks like:
                    // "/sites/BF5/Lists/Announcements/DispForm.aspx?ID=2&Source=http%3A%2F%2Fcollab%2Fsites%2FBF5%2Fdefault%2Easpx"
                    // the following isolates the site collection base url and then forms the redirect to the changeqa page
                    // relative the site collection URL.
                    // 
                    // If a logon starts from the logoff result page then there is nothing to strip so catch the exception

                    // For logons to the root site collection, this breaks miserably. 
                    // If the target URL is "/Lists/Announcements/DispForm.aspx?ID=2&Source=http%3A%2F%2Fcollab%2Fsites%2FBF5%2Fdefault%2Easpx"
                    // Then the code tries to isolate the site collection path component and finds /Lists/Announcements/ - 
                    // which is both dumb and wrong. We are probably making this way harder then it actually is.

                    string qsUrl = Request.QueryString["ReturnUrl"];
                    
                    try
                    {
                        // the following works for everything except for logons to the root site collection
                        int myind = qsUrl.IndexOf('/', 1) + 1;
                        qsUrl = qsUrl.Remove(qsUrl.IndexOf('/', qsUrl.IndexOf('/', 1) + 1));
                    }
                    catch
                    {
                    }

 
                    Response.Redirect(
                         HttpUtility.UrlPathEncode(qsUrl) + 
                         "/_layouts/ExternalCollaboration/changeqa.aspx?ReturnUrl="
                         + Request.QueryString["ReturnUrl"]
                         );
                }
                else
                {
                    FormsAuthentication.RedirectFromLoginPage(
                                            LoginControl.UserName,
                                            false
                                            );
                }

            }
        }

        void Page_Init()
        {
            PasswordRecovery_Init();
        }
    }
    /*++
      class PasswordResetPage
     
    --*/

    public class PasswordResetPage : Microsoft.SharePoint.WebControls.UnsecuredLayoutsPageBase
    {
        //
        // Configuration helper class that allows the page to query
        // the SQL configuration for Sharepoint.
        //
        protected System.Web.UI.WebControls.PasswordRecovery PRControl;
        protected override bool AllowAnonymousAccess { get { return true; } }
        protected override bool AllowNullWeb { get { return true; } }
        protected Label lblPR;

        public PasswordResetPage()
        {
        }

        public void PR_OnVerifyingUser(object sender, System.Web.UI.WebControls.LoginCancelEventArgs e)
        {
            MembershipUser u = null;
            try
            {
                u = Membership.GetUser(PRControl.UserName);
            }
            catch (Exception)
            {
                return;
            }
            if (u != null && u.PasswordQuestion == "[change the secret question]")
            {
                lblPR.Text = Resources.prNoQuestion;
                e.Cancel = true;
            }
        }

        void Page_Init()
        {
        }
    }

    public class Receiver : SPFeatureReceiver
    {
        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            SPWebApplication spWebApp = (SPWebApplication)properties.Feature.Parent;

            foreach (SPUrlZone spZone in spWebApp.IisSettings.Keys)
            {
                SPIisSettings spSettings = spWebApp.IisSettings[spZone];

                string fromPath = Path.Combine(SPUtility.GetGenericSetupPath("Template"),
                    "FEATURES\\ExternalCollaboration\\ExternalCollaboration.resx");

                string toPath = Path.Combine(spSettings.Path.ToString(),
                    "App_GlobalResources\\ExternalCollaboration.resx");

                File.Copy(fromPath, toPath, true);
            }
        }

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            SPWebApplication spWebApp = (SPWebApplication)properties.Feature.Parent;

            foreach (SPUrlZone spZone in spWebApp.IisSettings.Keys)
            {
                SPIisSettings spSettings = spWebApp.IisSettings[spZone];

                string filePath = Path.Combine(spSettings.Path.ToString(),
                    "App_GlobalResources\\ExternalCollaboration.resx");

                try
                {
                    File.Delete(filePath);
                }
                catch (Exception)
                {
                }
            }
        }

        public override void FeatureInstalled(SPFeatureReceiverProperties properties)
        {
        }

        public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
        {
        }
    }
}
